#include "MarsPrecompile.h"
#include "MarsCLMgr.h"
#include "MarsCLPlatform.h"
#include "MarsCLContext.h"

using namespace GP;

bool CLMgr::Initialize()
{
	cl_int status = CL_SUCCESS;
	cl_uint numPlatforms;
	cl_platform_id platform = NULL;

	status = clGetPlatformIDs( 0, NULL, &numPlatforms );
	if ( status != CL_SUCCESS )
	{
		// std::cout<<"Error: clGetPlatformIDs failed. Error code : ";
		// std::cout << streamsdk::getOpenCLErrorCodeStr(status) << std::endl;
		return false;
	}

	if ( numPlatforms > 0 )
	{
		cl_platform_id* platforms = new cl_platform_id[ numPlatforms ];

		struct CleanupObject
		{
			CleanupObject( cl_platform_id* platforms ) : m_platforms( platforms )
			{}

			~CleanupObject() 
			{
				SAFE_DELETE_ARRAY( m_platforms );
			}

			cl_platform_id* m_platforms;
		} cleanupObject( platforms );

		// Get selected platform
		status = clGetPlatformIDs( numPlatforms, platforms, NULL );

		if ( status != CL_SUCCESS )
		{
			//std::cout<<"Error: clGetPlatformIDs failed. Error code : ";
			//std::cout << streamsdk::getOpenCLErrorCodeStr(status) << std::endl;

			
			return false;
		}

		for ( Core::uint32 i = 0; i < numPlatforms; ++i )
		{
			char pbuf[ 50 ];
			status = clGetPlatformInfo( platforms[ i ],
										CL_PLATFORM_VENDOR,
										sizeof( pbuf ),
										pbuf,
										NULL );

			if ( status != CL_SUCCESS )
			{
				//std::cout<<"Error: clGetPlatformInfo failed. Error code : ";
				//std::cout << streamsdk::getOpenCLErrorCodeStr(status) << std::endl;
				continue;
			}

			if ( MARS_STREQUAL( pbuf, "Advanced Micro Devices, Inc." ) )
			{
				PlatformPtr platform = new CLPlatform( PlatformVendor_AMD, platforms[ i ] );
				platform->InitDevice();

				m_vecPlatforms.push_back( platform );
			}
		}
	}

}

void CLMgr::SetCurrentPlatform( PlatformVendor ePlatform )
{
	PlatformVecItr it = m_vecPlatforms.begin();
	PlatformVecItr end = m_vecPlatforms.end();

	for ( ; it != end; ++it )
	{
		PlatformPtr& platform = ( *it );

		if ( platform->GetPlatformVendor() == ePlatform )
		{
			m_ePlatform = ePlatform;
		}
	}
}

ContextPtr CLMgr::CreateContext( const DevicePtr& device )
{
	MARS_ASSERT( m_ePlatform != PlatformVendor_Unknown );

	if ( device->GetPlatform() != m_ePlatform)
	{
		return ContextPtr();
	}

	ContextPtr context = new CLContext( device );

	return context;
}

cl_platform_id CLMgr::GetCurrentPlatformId() const
{
	MARS_ASSERT( m_ePlatform != PlatformVendor_Unknown );

	return ( ( CLPlatform* ) m_platform.GetPointer()->GetPlatformId() );
}
